package com.wjy.icu.websocket.server;



import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.wjy.icu.common.CacheManage;
import com.wjy.icu.common.core.domain.R;
import com.wjy.icu.common.exception.MqttException;
import com.wjy.icu.domain.*;
import com.wjy.icu.domain.vo.BluetoothVo;
import com.wjy.icu.emqx.utils.MqttUtils;
import com.wjy.icu.service.IBluetoochService;
import com.wjy.icu.service.IMqttService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description:
 * @author: wangjunyong
 * @date: 2020/12/28 18:03
 */
@ServerEndpoint("/console/{userId}/{mac}")
@Component
public class WebSocketServer {

    static Log log= LogFactory.get(WebSocketServer.class);
    /**静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    /**concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。*/
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<String,String> webUserMacMap = new ConcurrentHashMap<>();
    /**与某个客户端的连接会话，需要通过它来给客户端发送数据*/
    private Session session;
    /**接收userId*/
    private String userId="";
    /**接收mac*/
    private String mac="";

    static CacheManage cacheManage;
    static IMqttService mqttService;
    static IBluetoochService bluetoochService;
    @Autowired
    public void setMqttService(IMqttService mqttService){
        WebSocketServer.mqttService = mqttService;
    }
    @Autowired
    public void setBluetoochService(IBluetoochService bluetoochService){
        WebSocketServer.bluetoochService = bluetoochService;
    }
    @Autowired
    public void setCacheManage(CacheManage cacheManage){
        WebSocketServer.cacheManage = cacheManage;
    }
    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId, @PathParam("mac") String mac) {
        this.session = session;
        this.userId=userId;
        this.mac = mac;
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            webUserMacMap.remove(userId);
            webSocketMap.put(userId,this);
            webUserMacMap.put(userId,mac);
            //加入set中
        }else{
            webSocketMap.put(userId,this);
            webUserMacMap.put(userId,mac);
            //加入set中
            addOnlineCount();
            //在线数加1
        }
        log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
        log.info("webUserMacMap："+webUserMacMap);
        try {
            if (session.isOpen()) {
                sendEquipmentToUser();
            }
        } catch (IOException e) {
            log.error("用户:"+userId+",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            webUserMacMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
//        log.info("session:"+session);
        log.info("webUserMacMap："+webUserMacMap);
        log.info("webSocketMap："+webSocketMap);
        log.info("用户消息:"+userId+",报文:"+message);
        if(!webSocketMap.containsKey(userId)){
            sendNullUser();
        }else {
            JSONObject json = JSON.parseObject(message);
            Integer messageType = json.getInteger("messageType");
            if (messageType != 1) {
                //心跳连接
            } else {
                String type = json.getString("type");
                JSONObject message1 = json.getJSONObject("message");
                String mac = json.getString("mac");
                if (session.isOpen()) {
                    doComplete(type, mac, message1);
                    sendEquipmentToUser();
                }
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public void sendNullUser() throws IOException {

        R error = R.error("暂无此用户，请刷新重进");
        String s = JSON.toJSONString(error,SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
        sendMessage(s);
    }

    public void sendEquipmentToUser() throws IOException {
        Equipment equipment = mqttService.findByMac(mac);
        Integer id = equipment.getId();
        EquipmentFunc equipmentFunc = mqttService.findByEquipId(id);
        EquipmentFunc.parse(equipmentFunc);
        equipment.setEquipmentFunc(equipmentFunc);
        //TODO 设置宠物温度，蓝牙状态
        BluetoothVo bluetoothVo = bluetoochService.findByEquitId(id);
        equipment.setBluetoothVo(bluetoothVo);

        String s = JSON.toJSONString(equipment,SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
        sendMessage(s);
    }

    /**
     *  实际操作

     */
    public void doComplete(String type,String mac,JSONObject message)  {
        switch (MqttUpEnum.getByCode(type)){
            case link:
                break;
            case mainTempSetting:
                String mainTempSetting = message.getString("mainTempSetting");
                String s = MqttUtils.lowHigh(mainTempSetting);
                mqttService.sendEquitment(mac,type,s);
                break;
            case buttomTempSetting:
                String buttomTempSetting = message.getString("buttomTempSetting");
                String ss = MqttUtils.lowHigh(buttomTempSetting);
                mqttService.sendEquitment(mac,type,ss);
                break;
            case humiditySetting:
                String humiditySetting = message.getString("humiditySetting");
                String s1 = MqttUtils.lowHigh2(humiditySetting);
                mqttService.sendEquitment(mac,type,s1);
                break;
            case oxygenConcentrationSetting:
                String oxygenConcentrationSetting = message.getString("oxygenConcentrationSetting");
                String s2 = MqttUtils.lowHigh2(oxygenConcentrationSetting);
                mqttService.sendEquitment(mac,type,s2);
                break;
            case cycleState:
                String cycleState = message.getString("cycleState");
                String s3 = MqttUtils.lowHigh2(cycleState);
                mqttService.sendEquitment(mac,type,s3);
                break;
            case negativeIonSwitch:
                String negativeIonSwitch = message.getString("negativeIonSwitch");
                String s4 = MqttUtils.lowHigh2(negativeIonSwitch);
                mqttService.sendEquitment(mac,type,s4);
                break;
            case uv:
                String uv = message.getString("uv");
                String s5 = MqttUtils.lowHigh2(uv);
                mqttService.sendEquitment(mac,type,s5);
                break;
            case floodlight:
                String floodlight = message.getString("floodlight");
                String s6 = MqttUtils.lowHigh2(floodlight);
                mqttService.sendEquitment(mac,type,s6);
                break;
            case inspectionLamp:
                String inspectionLamp = message.getString("inspectionLamp");
                String s7 = MqttUtils.lowHigh2(inspectionLamp);
                mqttService.sendEquitment(mac,type,s7);
                break;
            case petSite:
                String petSite = message.getString("petSite");
                String s8 = MqttUtils.lowHigh2(petSite);
                mqttService.sendEquitment(mac,type,s8);
                break;
            case atomizerTreatmentTime:
                String atomizerTreatmentTime = message.getString("atomizerTreatmentTime");
                String s9 = MqttUtils.lowHigh2(atomizerTreatmentTime);
                mqttService.sendEquitment(mac,type,s9);
                break;
            case infraredPhysiotherapyTime:
                String infraredPhysiotherapyTime = message.getString("infraredPhysiotherapyTime");
                String sA = MqttUtils.lowHigh2(infraredPhysiotherapyTime);
                mqttService.sendEquitment(mac,type,sA);
                break;
            case regulationMode0:
                //设置成自动模式
                mqttService.modelUpdate("manual",mac);
                break;
            case regulationMode1:
                //设置成预设模式
                mqttService.modelUpdate("preset",mac);
                break;
            case regulationModeSetting:
                //预设模式设置
                String type1 = message.getString("type");
                Integer planType = message.getInteger("planType");
                String buttomTemp = message.getString("buttomTemp");
                String cabinTemp = message.getString("cabinTemp");
                String petTemp = message.getString("petTemp");
                Integer id = message.getInteger("id");
                Integer userId = message.getInteger("userId");
                Integer equipmentId = message.getInteger("equipmentId");
                PresetModelsCondition presetModelsCondition = new PresetModelsCondition();
                switch (type1){
                    case "add":
                        presetModelsCondition.setModel(planType);
                        presetModelsCondition.setUserId(userId);
                        presetModelsCondition.setEquitmentId(equipmentId);
                        presetModelsCondition.setGmtCreate(LocalDateTime.now());
                        if (planType==1){
                            presetModelsCondition.setBigger(new BigDecimal(petTemp));
                        }else {
                            presetModelsCondition.setLower(new BigDecimal(petTemp));
                        }
                        presetModelsCondition.setCabinTemperatureSetting(cabinTemp);
                        presetModelsCondition.setThermostatTreatmentTemperatureSetting(buttomTemp);
                        mqttService.addRegulateMode(presetModelsCondition);
                        break;
                    case "update":
                        presetModelsCondition.setId(id);
                        presetModelsCondition.setModel(planType);
                        presetModelsCondition.setUserId(userId);
                        presetModelsCondition.setEquitmentId(equipmentId);
                        presetModelsCondition.setGmtCreate(LocalDateTime.now());
                        if (planType==1){
                            presetModelsCondition.setBigger(new BigDecimal(petTemp));
                        }else {
                            presetModelsCondition.setLower(new BigDecimal(petTemp));
                        }
                        presetModelsCondition.setCabinTemperatureSetting(cabinTemp);
                        presetModelsCondition.setThermostatTreatmentTemperatureSetting(buttomTemp);
                        mqttService.updateRegulateMode(presetModelsCondition);
                        break;
                    case "delete":
                        mqttService.deleteRegulateMode(id);
                        break;
                    default:
                        throw new MqttException("不支持该类型上传数据");
                }
                break;
            default:
                throw new MqttException("不支持该类型上传数据");
        }
    }
    /**
     * 发送自定义消息
     * */
    public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
        log.info("发送消息到:"+userId+"，报文:"+message);
        if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
            webSocketMap.get(userId).sendEquipmentToUser();
        }else{
            log.error("用户"+userId+",不在线！");
        }
    }
    /**
     * 发送自定义消息
     * */
    public static void sendMacInfo(String message,String mac) throws IOException {
        ArrayList<String> keyList = new ArrayList<String>();
        String key = null;
        Set<Map.Entry<String, String>> set = webUserMacMap.entrySet();
        Iterator<Map.Entry<String, String>> iterator = set.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, String> entry  = iterator.next();
            if (entry.getValue().equals(mac)){
                key = (String) entry.getKey();
                keyList.add(key);
            }
        }

        for (String userId : keyList) {
            if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
                if(webSocketMap.get(userId).session.isOpen()) {
                    webSocketMap.get(userId).sendEquipmentToUser();
                }
            }else{
                log.error("用户"+userId+",不在线！");
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}
